package com.zzyl.nursing.service.impl;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONUtil;
import com.aliyun.iot20180120.Client;
import com.aliyun.iot20180120.models.*;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.zzyl.common.constant.CacheConstants;
import com.zzyl.common.core.domain.AjaxResult;
import com.zzyl.common.exception.base.BaseException;
import com.zzyl.framework.config.properties.AliIoTConfigProperties;
import com.zzyl.nursing.dto.DeviceDto;
import com.zzyl.nursing.vo.DeviceVo;
import com.zzyl.nursing.vo.ProductVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import com.zzyl.nursing.mapper.DeviceMapper;
import com.zzyl.nursing.domain.Device;
import com.zzyl.nursing.service.IDeviceService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.transaction.annotation.Transactional;

/**
 * 设备Service业务层处理
 * 
 * @author zhai
 * @date 2025-01-10
 */
@Service
public class DeviceServiceImpl extends ServiceImpl<DeviceMapper, Device> implements IDeviceService
{
    @Autowired
    private DeviceMapper deviceMapper;

    @Autowired
    private Client client;

    @Autowired
    private AliIoTConfigProperties aliIoTConfigProperties;

    @Autowired
    private RedisTemplate<String,String> redisTemplate;

    /**
     * 查询设备
     * 
     * @param id 设备主键
     * @return 设备
     */
    @Override
    public Device selectDeviceById(Long id)
    {
        return deviceMapper.selectById(id);
    }

    /**
     * 查询设备列表
     * 
     * @param device 设备
     * @return 设备
     */
    @Override
    public List<Device> selectDeviceList(Device device)
    {
        return deviceMapper.selectDeviceList(device);
    }

    /**
     * 新增设备
     * 
     * @param device 设备
     * @return 结果
     */
    @Override
    public int insertDevice(Device device)
    {
        return deviceMapper.insert(device);
    }

    /**
     * 修改设备
     * 
     * @param device 设备
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int updateDevice(Device device)
    {
        //1.修改数据库设备信息
        int result = deviceMapper.updateById(device);
        if (result == 0){
            throw new BaseException("修改数据库设备失败");
        }
        //2.修改Iot平台上的设备数据信息
        BatchUpdateDeviceNicknameRequest request = new BatchUpdateDeviceNicknameRequest();
        request.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId());
        //response批量更新要接收一个List集合
        List<BatchUpdateDeviceNicknameRequest.BatchUpdateDeviceNicknameRequestDeviceNicknameInfo> nickNameInfos = new ArrayList<>();
        //为List集合设置前端所需要的参数
        BatchUpdateDeviceNicknameRequest.BatchUpdateDeviceNicknameRequestDeviceNicknameInfo nickNameInfo = new BatchUpdateDeviceNicknameRequest.BatchUpdateDeviceNicknameRequestDeviceNicknameInfo();
        nickNameInfo.setDeviceName(device.getDeviceName());
        nickNameInfo.setIotId(device.getIotId());
        nickNameInfo.setNickname(device.getNickname());
        //将nickNameInfo添加到List集合中
        nickNameInfos.add(nickNameInfo);
        request.setDeviceNicknameInfo(nickNameInfos);
        BatchUpdateDeviceNicknameResponse response;
        try {
            response = client.batchUpdateDeviceNickname(request);
        } catch (Exception e) {
            throw new BaseException("更新iot平台设备失败");
        }
        if (!response.getBody().getSuccess()){
            throw new BaseException("更新iot平台设备失败");
        }

        return result;
    }

    /**
     * 批量删除设备
     * 
     * @param ids 需要删除的设备主键
     * @return 结果
     */
    @Override
    public int deleteDeviceByIds(Long[] ids)
    {
        return deviceMapper.deleteBatchIds(Arrays.asList(ids));
    }

    /**
     * 删除设备信息
     * 
     * @param id 设备主键
     * @return 结果
     */
    @Override
    public int deleteDeviceById(Long id)
    {
        return deviceMapper.deleteById(id);
    }

    /**
     * 同步产品列表
     */
    @Override
    public void syncProductList() {
        //1.调用IOT平台查询所有同步列表
        QueryProductListRequest request = new QueryProductListRequest();
        request.setPageSize(100);
        request.setCurrentPage(1);
        request.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId());

        QueryProductListResponse response;
        try {
            response = client.queryProductList(request);
        } catch (Exception e) {
            throw new BaseException("同步列表失败");
        }

        if (!response.getBody().success){
            throw new BaseException("同步列表失败");
        }

        List<QueryProductListResponseBody.QueryProductListResponseBodyDataListProductInfo> productList = response.body.data.list.productInfo;
        String productListJson = JSONUtil.toJsonPrettyStr(productList);
        //2.将查询到的列表存放到Redis缓存中
        redisTemplate.opsForValue().set(CacheConstants.IOT_PRODUCT_LIST,productListJson);
    }

    /**
     * 查询所有产品列表
     *
     * @return
     */
    @Override
    public List<ProductVo> allProduct() {
        //1.通过Redis缓存获取到同步列表的数据
        String productListStr = redisTemplate.opsForValue().get(CacheConstants.IOT_PRODUCT_LIST);
        //2.将查询到的json列表转换为List数据，直接返回前端页面
        List<ProductVo> list = JSONUtil.toList(productListStr, ProductVo.class);
        return list;
    }

    /**
     * 注册设备
     *
     * @param deviceDto 前端传递的设备数据
     */
    @Override
    public void register(DeviceDto deviceDto) {
        //1.查询数据库，判断设备名称是否重复
        Long count = deviceMapper.selectCount(Wrappers.<Device>lambdaQuery()
                .eq(Device::getDeviceName, deviceDto.getDeviceName()));
        //2.如果重复直接结束
        if (count > 0 ){
            throw new BaseException("设备名称重复，请重新输入");
        }
        //3.如果查询不重复，调用IOT平台方法保存到iot平台上
        RegisterDeviceRequest result = deviceDto.getRegisterDeviceRequest();
        result.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId());
        RegisterDeviceResponse response;
        try {
             response = client.registerDevice(result);
        } catch (Exception e) {
            throw new BaseException("物联网接口 - 注册设备，调用失败");
        }
        //判断是否调用成功
        if (!response.getBody().getSuccess()){
            throw new BaseException("物联网接口 - 注册设备，调用失败");
        }
        //4.判断位置类型是否为0，如果为0，是随身设置，将物理位置更改为-1
        if (deviceDto.getLocationType() == 0){
            deviceDto.setPhysicalLocationType(-1);
        }
        //5.补充新增时返回的iotid
        String iotId = response.getBody().getData().getIotId();
        //6.保存到数据库中
        deviceDto.setIotId(iotId);
        Device device = BeanUtil.toBean(deviceDto, Device.class);
        try {
            int insert = deviceMapper.insert(device);
            if (insert == 0){
            deleteIotDevice(device);
            throw new BaseException("该老人/位置已绑定该产品，请重新选择");
            }
        } catch (Exception e) {
            //7.如果保存失败，则删除ipt平台上新增的设备数据
            try {
                deleteIotDevice(device);
            } catch (Exception ex) {
                throw new BaseException("物联网接口 - 删除设备，调用失败");
            }
            throw new BaseException("该老人/位置已绑定该产品，请重新选择");
        }

    }

    /**
     * 删除设备
     * @param device
     * @throws Exception
     */
    private void deleteIotDevice(Device device) throws Exception {
        DeleteDeviceRequest deleteDeviceRequest = new DeleteDeviceRequest();
        deleteDeviceRequest.setDeviceName(device.getDeviceName());
        deleteDeviceRequest.setIotId(device.getIotId());
        deleteDeviceRequest.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId());
        deleteDeviceRequest.setProductKey(device.getProductKey());
        client.deleteDevice(deleteDeviceRequest);
    }

    /**
     * @param deviceDto
     * @return
     */
    @Override
    public DeviceVo queryDeviceDetail(DeviceDto deviceDto) {
        //1.查询IOT平台上的设备信息
        QueryDeviceDetailRequest request = new QueryDeviceDetailRequest();
        request.setIotId(deviceDto.getIotId());
        request.setProductKey(deviceDto.getProductKey());
        request.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId());
        QueryDeviceDetailResponse response;
        try {
            response = client.queryDeviceDetail(request);
        } catch (Exception e) {
            throw new BaseException("查询IOT平台上的设备信息失败");
        }
        if (!response.body.success){
            throw new BaseException("查询IOT平台上的设备信息失败");
        }
        //将查询到的iot平台上的设备信息拷贝到DeviceVo上
        DeviceVo deviceVo = BeanUtil.toBean(response.getBody().getData(), DeviceVo.class);
        //2.查询数据库中的设备信息
        Device device = deviceMapper.selectOne(Wrappers.<Device>lambdaQuery()
                .eq(Device::getIotId, deviceDto.getIotId()));
        //将查询到的数据库中信息拷贝到DeviceVo上
        BeanUtil.copyProperties(device, deviceVo);
        //3.合并查询到的俩个信息，返回结果
        return  deviceVo;
    }

    /**
     * 查询物模型
     *
     * @param request IO平台传递的数据
     * @return 返回物模型
     */
    @Override
    public Object queryThingModelPublished(QueryThingModelPublishedRequest request) {
    request.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId());
    QueryThingModelPublishedResponse response;
        try {
            response =client.queryThingModelPublished(request);
        } catch (Exception e) {
            throw new BaseException("返回物模型信息失败");
        }
        if (!response.getBody().getSuccess()){
            throw new BaseException("返回物模型信息失败");
        }
        //查询已发布物模型中的功能定义详情成功
        return response.getBody().getData();
    }

    /**
     * 查询指定设备的物模型运行状态
     *
     * @param request iot平台传递的前端对象数据
     * @return 返回物模型运行状态
     */
    @Override
    public AjaxResult queryDevicePropertyStatus(QueryDevicePropertyStatusRequest request) {
        request.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId());
        QueryDevicePropertyStatusResponse response;
        try {
            response = client.queryDevicePropertyStatus(request);
        } catch (Exception e) {
            throw new BaseException("返回物模型运行状态数据失败");
        }
        if (!response.getBody().getSuccess()){
            throw new BaseException("返回物模型运行状态数据失败");
        }
        //返回物模型运行状态数据成功，返回前端
        return AjaxResult.success(response.getBody().getData());
    }

    /**
     * 删除设备
     *
     * @param deviceDto 前端传递的设备信息
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public AjaxResult deleteDevice(DeviceDto deviceDto) {
        //1.删除数据库中的设备信息
        int delete = deviceMapper.delete(Wrappers.<Device>lambdaQuery()
                .eq(Device::getIotId, deviceDto.getIotId())
                .eq(Device::getProductKey,deviceDto.getProductKey()));
        if (ObjectUtil.isEmpty(delete)){
            throw new BaseException("删除数据库中设备信息失败");
        }
        //2.删除iot平台上的设备信息
        DeleteDeviceRequest request = new DeleteDeviceRequest();
        request.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId());
        request.setProductKey(deviceDto.getProductKey());
        request.setIotId(deviceDto.getIotId());
        DeleteDeviceResponse response;
        try {
             response = client.deleteDevice(request);
        } catch (Exception e) {
            throw new BaseException("删除设备信息失败");
        }
        if (!response.getBody().getSuccess()){
            throw new BaseException("删除设备信息失败");
        }
        return AjaxResult.success();
    }
}
